package com.houger.ddd.seckill.application;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.houger.ddd.common.base.BaseExtDataDto;
import com.houger.ddd.common.utils.ClassTypeUtils;
import com.houger.ddd.seckill.constant.*;
import com.houger.ddd.seckill.domian.check.AllUserAcceptCheck;
import com.houger.ddd.seckill.facade.dto.*;
import com.houger.ddd.seckill.infra.entity.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @author Houger
 */
public class MapperUtils {

    public static <T> void setIfNull(final Consumer<T> setter, final Object value, final T defaultV) {
        if (value == null) {
            setter.accept(defaultV);
        }
    }

    public static ActivityTemplateBasicDto getBasicDto(ActivityTemplateBasic basic) {
        ActivityTemplateBasicDto basicDto = new ActivityTemplateBasicDto();
        return getBasicDto(basic, basicDto);
    }

    public static ActivityTemplateBasicDto getBasicDto(ActivityTemplateBasic basic, ActivityTemplateBasicDto basicDto) {
        BeanUtils.copyProperties(basic, basicDto);
        setBasicDtoDefault(basicDto);
        return basicDto;
    }

    public static ActivityTemplateBasic getBasic(ActivityTemplateBasicDto basicDto) {
        ActivityTemplateBasic basic = ActivityTemplateBasic.builder().build();
        BeanUtils.copyProperties(basicDto, basic);
        return basic;
    }

    public static ActivityTemplateBasicDto setBasicDtoDefault(ActivityTemplateBasicDto basicDto) {
        setIfNull(basicDto::setTemplateStatus, basicDto.getTemplateStatus(), TemplateStatusEnum.INIT.getValue());
        setIfNull(basicDto::setTemplateCode, basicDto.getTemplateCode(), "");
        setIfNull(basicDto::setTemplateName, basicDto.getTemplateName(), "");
        setIfNull(basicDto::setTemplateTypeClass, basicDto.getTemplateTypeClass(), "");
        setIfNull(basicDto::setActivityTag, basicDto.getActivityTag(), "");
        setIfNull(basicDto::setApplyPlatforms, basicDto.getApplyPlatforms(), "");
        setIfNull(basicDto::setApplyShopType, basicDto.getApplyShopType(), ApplyShopTypeEnum.ALL.getValue());
        setIfNull(basicDto::setApplyShopGroupId, basicDto.getApplyShopGroupId(), 0L);
        setIfNull(basicDto::setAuditBy, basicDto.getAuditBy(), "");
        setIfNull(basicDto::setAuditMemo, basicDto.getAuditMemo(), "");
        if(StringUtils.isNotEmpty(basicDto.getTemplateTypeClass())){
            setIfNull(basicDto::setTemplateType, basicDto.getTemplateType(), ActivityTypeEnum.getEnumTemplateTypeClass(basicDto.getTemplateTypeClass()).getType());
        }
        setIfNull(basicDto::setActivitySort, basicDto.getActivitySort(), 0);
        setIfNull(basicDto::setSuperposeDiscount, basicDto.getSuperposeDiscount(), 0);
        return basicDto;
    }

    public static ActivityTemplateBizConfigDto getBizConfigDto(
        ActivityTemplateBizConfig bizConfig,
        Class<? extends BaseExtDataDto> extDataObjClass) {
        ActivityTemplateBizConfigDto bizConfigDto = new ActivityTemplateBizConfigDto();
        return getBizConfigDto(bizConfig, bizConfigDto, extDataObjClass);
    }

    public static ActivityTemplateBizConfigDto getBizConfigDto(
        ActivityTemplateBizConfig bizConfig,
        ActivityTemplateBizConfigDto bizConfigDto,
        Class<? extends BaseExtDataDto> extDataObjClass) {
        BeanUtils.copyProperties(bizConfig,bizConfigDto);
        if (extDataObjClass != null) {
            if (bizConfig.getExtData() != null) {
                bizConfigDto.setExtDataObj(JSON.parseObject(bizConfig.getExtData(), extDataObjClass));
                bizConfigDto.setExtDataJson(null);
            }
        }
        setBizConfigDtoDefault(bizConfigDto, extDataObjClass);
        return bizConfigDto;
    }

    public static void setBizConfigDtoDefault(ActivityTemplateBizConfigDto bizConfigDto, Class<? extends BaseExtDataDto> extDataObjClass) {
        setIfNull(bizConfigDto::setTokenIssueType, bizConfigDto.getTokenIssueType(), TokenIssueTypeEnum.AUTO_CALC.getValue());
        setIfNull(bizConfigDto::setInstanceOpeningMax, bizConfigDto.getInstanceOpeningMax(), 1);
        setIfNull(bizConfigDto::setInstanceCloseType, bizConfigDto.getInstanceCloseType(), InstanceCloseTypeEnum.NOT_CLOSE.getValue());
        setIfNull(bizConfigDto::setInstanceCloseAfter, bizConfigDto.getInstanceCloseAfter(), LimitConstant.ZERO);
        setIfNull(bizConfigDto::setInitiatorCheckClass, bizConfigDto.getInitiatorCheckClass(), AllUserAcceptCheck.class.getName());
        setIfNull(bizConfigDto::setInitiatorGroupId, bizConfigDto.getInitiatorGroupId(), 0L);
        setIfNull(bizConfigDto::setPlayerCheckClass, bizConfigDto.getPlayerCheckClass(), AllUserAcceptCheck.class.getName());
        setIfNull(bizConfigDto::setPlayerGroupId, bizConfigDto.getPlayerGroupId(), 0L);
        setIfNull(bizConfigDto::setInitiatorRewardIssueType, bizConfigDto.getInitiatorRewardIssueType(), RewardIssueTypeEnum.NOT_ISSUE.getValue());
        setIfNull(bizConfigDto::setInitiatorRewardCloseType, bizConfigDto.getInitiatorRewardCloseType(), RewardCloseTypeEnum.NOT_CLOSE.getValue());
        setIfNull(bizConfigDto::setInitiatorRewardCloseAfter, bizConfigDto.getInitiatorRewardCloseAfter(), LimitConstant.ZERO);
        setIfNull(bizConfigDto::setPlayerRewardIssueType, bizConfigDto.getPlayerRewardIssueType(), RewardIssueTypeEnum.NOT_ISSUE.getValue());
        setIfNull(bizConfigDto::setPlayerRewardCloseType, bizConfigDto.getPlayerRewardCloseType(), RewardCloseTypeEnum.NOT_CLOSE.getValue());
        setIfNull(bizConfigDto::setPlayerRewardCloseAfter, bizConfigDto.getPlayerRewardCloseAfter(), LimitConstant.ZERO);
        setIfNull(bizConfigDto::setTemplateInitiatorMax, bizConfigDto.getTemplateInitiatorMax(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setTemplatePlayerMax, bizConfigDto.getTemplatePlayerMax(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setTemplateInitiatorDailyMax, bizConfigDto.getTemplateInitiatorDailyMax(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setTemplatePlayerDailyMax, bizConfigDto.getTemplatePlayerDailyMax(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setTemplateInitiatorRewardMax, bizConfigDto.getTemplateInitiatorRewardMax(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setTemplatePlayerRewardMax, bizConfigDto.getTemplatePlayerRewardMax(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setTemplateInitiatorDailyRewardMax, bizConfigDto.getTemplateInitiatorDailyRewardMax(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setTemplatePlayerDailyRewardMax, bizConfigDto.getTemplatePlayerDailyRewardMax(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setInstancePlayerLimit, bizConfigDto.getInstancePlayerLimit(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setInstancePlayerRewardLimit, bizConfigDto.getInstancePlayerRewardLimit(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setInstancePlayerMax, bizConfigDto.getInstancePlayerMax(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setInstancePlayerDailyMax, bizConfigDto.getInstancePlayerDailyMax(), LimitConstant.NO_LIMIT);
        setIfNull(bizConfigDto::setInstancePlayerDailyRewardMax, bizConfigDto.getInstancePlayerDailyRewardMax(), LimitConstant.NO_LIMIT);
        if (bizConfigDto.getExtDataJson() != null) {
            bizConfigDto.setExtDataObj(bizConfigDto.getExtDataJson().toJavaObject(extDataObjClass));
            bizConfigDto.setExtDataJson(null);
        }
    }

    public static ActivityTemplateBizConfig getBizConfig(ActivityTemplateBizConfigDto bizConfigDto) {
        ActivityTemplateBizConfig bizConfig = ActivityTemplateBizConfig.builder().build();
        BeanUtils.copyProperties(bizConfigDto, bizConfig);
        if (bizConfigDto.getExtDataObj() == null) {
            bizConfig.setExtData("{}");
        } else {
            bizConfig.setExtData(JSON.toJSONString(bizConfigDto.getExtDataObj()));
        }
        return bizConfig;
    }

    public static ActivityTemplateUiConfigDto getUiConfigDto(
        ActivityTemplateUiConfig uiConfig,
        Class<? extends BaseExtDataDto> extDataObjClass) {
        ActivityTemplateUiConfigDto uiConfigDto = new ActivityTemplateUiConfigDto();
        return getUiConfigDto(uiConfig, uiConfigDto, extDataObjClass);
    }

    public static ActivityTemplateUiConfigDto getUiConfigDto(
        ActivityTemplateUiConfig uiConfig,
        ActivityTemplateUiConfigDto uiConfigDto,
        Class<? extends BaseExtDataDto> extDataObjClass) {
        BeanUtil.copyProperties(uiConfig, uiConfigDto);
        if (extDataObjClass != null) {
            if (uiConfig.getExtData() != null && !"{}".equals(uiConfig.getExtData())) {
                uiConfigDto.setExtDataObj(JSON.parseObject(uiConfig.getExtData(), extDataObjClass));
                uiConfigDto.setExtDataJson(null);
            }
        }
        setUiConfigDtoDefault(uiConfigDto, extDataObjClass);
        return uiConfigDto;
    }

    public static void setUiConfigDtoDefault(
        ActivityTemplateUiConfigDto uiConfigDto,
        Class<? extends BaseExtDataDto> extDataObjClass) {
        setIfNull(uiConfigDto::setRuleDesc, uiConfigDto.getRuleDesc(), "");
        if (uiConfigDto.getExtDataJson() != null) {
            uiConfigDto.setExtDataObj(uiConfigDto.getExtDataJson().toJavaObject(extDataObjClass));
            uiConfigDto.setExtDataJson(null);
        }
    }

    public static ActivityTemplateUiConfig getUiConfig(ActivityTemplateUiConfigDto uiConfigDto) {
        ActivityTemplateUiConfig uiConfig = ActivityTemplateUiConfig.builder().build();
        BeanUtil.copyProperties(uiConfigDto, uiConfig);
        if (uiConfigDto.getExtDataObj() == null) {
            uiConfig.setExtData("{}");
        } else {
            uiConfig.setExtData(JSON.toJSONString(uiConfigDto.getExtDataObj()));
        }
        return uiConfig;
    }

    public static ActivityRewardItemDto getRewardItemDto(
        ActivityRewardItem rewardItem,
        Class<? extends BaseExtDataDto> extDataObjClass) {
        ActivityRewardItemDto rewardItemDto = new ActivityRewardItemDto();
        return getRewardItemDto(rewardItem, rewardItemDto,
            extDataObjClass);
    }

    private static ActivityRewardItemDto getRewardItemDto(
        ActivityRewardItem rewardItem,
        ActivityRewardItemDto rewardItemDto,
        Class<? extends BaseExtDataDto> extDataObjClass) {
        BeanUtil.copyProperties(rewardItem, rewardItemDto);
        if (extDataObjClass != null) {
            if (rewardItem.getExtData() != null) {
                rewardItemDto.setExtDataObj(JSON.parseObject(rewardItem.getExtData(), extDataObjClass));
                rewardItemDto.setExtDataJson(null);
            }
        }
        setRewardItemDtoDefault(rewardItemDto, extDataObjClass);
        return rewardItemDto;
    }

    public static ActivityRewardItemDto setRewardItemDtoDefault(
        ActivityRewardItemDto rewardItemDto,
        Class<? extends BaseExtDataDto> extDataObjClass) {
        setIfNull(rewardItemDto::setItemType, rewardItemDto.getItemType(), RewardItemTypeEnum.NONE.getValue());
        setIfNull(rewardItemDto::setItemCode, rewardItemDto.getItemCode(), "");
        setIfNull(rewardItemDto::setItemName, rewardItemDto.getItemName(), "");
        setIfNull(rewardItemDto::setItemIcon, rewardItemDto.getItemIcon(), "");
        setIfNull(rewardItemDto::setItemOrder, rewardItemDto.getItemOrder(), 0);
        setIfNull(rewardItemDto::setDailyReleaseLimit, rewardItemDto.getDailyReleaseLimit(), LimitConstant.NO_LIMIT);
        setIfNull(rewardItemDto::setPlayerRewardMax, rewardItemDto.getPlayerRewardMax(), LimitConstant.NO_LIMIT);
        setIfNull(rewardItemDto::setPlayerDailyRewardMax, rewardItemDto.getPlayerDailyRewardMax(), LimitConstant.NO_LIMIT);
        setIfNull(rewardItemDto::setInvLimitType, rewardItemDto.getInvLimitType(), InvLimitTypeEnum.LIMIT.getValue());
        setIfNull(rewardItemDto::setInvTotal, rewardItemDto.getInvTotal(), LimitConstant.NO_LIMIT);
        setIfNull(rewardItemDto::setInvUsed, rewardItemDto.getInvUsed(), 0);
        setIfNull(rewardItemDto::setIsDelete, rewardItemDto.getIsDelete(), IsDelete.NORMAL);
        setIfNull(rewardItemDto::setRewardCount, rewardItemDto.getRewardCount(), 1);
        if (rewardItemDto.getExtDataJson() != null) {
            rewardItemDto.setExtDataObj(rewardItemDto.getExtDataJson().toJavaObject(extDataObjClass));
            rewardItemDto.setExtDataJson(null);
        }
        return rewardItemDto;
    }

    public static ActivityRewardItem getRewardItem(ActivityRewardItemDto rewardItemDto) {
        ActivityRewardItem rewardItem = ActivityRewardItem.builder().build();
        BeanUtil.copyProperties(rewardItemDto, rewardItem);
        if (rewardItemDto.getExtDataObj() == null) {
            rewardItem.setExtData("{}");
        } else {
            rewardItem.setExtData(JSON.toJSONString(rewardItemDto.getExtDataObj()));
        }
        return rewardItem;
    }

    public static List<ActivityRewardItemDto> getRewardItemDtoList(
        List<ActivityRewardItem> rewardItemList,
        Class<? extends BaseExtDataDto> extDataObjClass) {
        List<ActivityRewardItemDto> rewardItemDtoList = rewardItemList
            .stream().map(pool -> getRewardItemDto(pool, extDataObjClass))
            .collect(Collectors.toList());
        return rewardItemDtoList;
    }

    public static List<ActivityRewardItem> getRewardItemList(List<ActivityRewardItemDto> rewardItemDtoList) {
        List<ActivityRewardItem> rewardItemList = rewardItemDtoList
            .stream().map(pool -> getRewardItem(pool))
            .collect(Collectors.toList());
        return rewardItemList;
    }

    public static void setInstanceDefault(ActivityInstance instance) {
        setIfNull(instance::setInstanceCode, instance.getInstanceCode(), "");
        setIfNull(instance::setInstanceStatus, instance.getInstanceStatus(), InstanceStatusEnum.NONE.getValue());
        setIfNull(instance::setPlatform, instance.getPlatform(), PlatformEnum.UNKNOW.getValue());
        setIfNull(instance::setInitiatorId, instance.getInitiatorId(), "");
        setIfNull(instance::setInitiatorPhone, instance.getInitiatorPhone(), "");
        setIfNull(instance::setInitiatorIcon, instance.getInitiatorIcon(), "");
        setIfNull(instance::setInitiatorNickname, instance.getInitiatorNickname(), "");
        setIfNull(instance::setInitiatorRewardItemId, instance.getInitiatorRewardItemId(), 0L);
        setIfNull(instance::setPlayerMaxLimit, instance.getPlayerMaxLimit(), LimitConstant.NO_LIMIT);
        setIfNull(instance::setPlayerRewardLimit, instance.getPlayerRewardLimit(), LimitConstant.NO_LIMIT);
        setIfNull(instance::setExtData, instance.getExtData(), "{}");
    }




    public static ActivityInstanceDto getInstanceDto(ActivityInstance instance, Class<? extends BaseExtDataDto> extDataObjClass) {
        ActivityInstanceDto instanceDto = new ActivityInstanceDto();
        BeanUtil.copyProperties(instance, instanceDto);
        if (extDataObjClass != null) {
            if (instance.getExtData() != null) {
                instanceDto.setExtDataObj(JSON.parseObject(instance.getExtData(), extDataObjClass));
                instanceDto.setExtDataJson(null);
            }
        }
        return instanceDto;
    }

    public static ActivityInstance getInstance(ActivityInstanceDto instanceDto) {
        ActivityInstance instance = ActivityInstance.builder().build();
        BeanUtil.copyProperties(instanceDto, instance);
        if (instanceDto.getExtDataObj() == null) {
            instance.setExtData("{}");
        } else {
            instance.setExtData(JSON.toJSONString(instanceDto.getExtDataObj()));
        }
        return instance;
    }

    @SuppressWarnings("all")
    public static <T> T copy(final Object f, final Class<T> t) {
//        BeanUtils.copyProperties(f, t, getNullPropertyNames(f));
        BeanUtil.copyProperties(f, t,getNullPropertyNames(f));
        return (T) t;
    }

    @SuppressWarnings("all")
    public static <T> T copy(final Object f, final Object t) {
        BeanUtil.copyProperties(f, t,getNullPropertyNames(f));
        return (T) t;
    }

    @SuppressWarnings("all")
    public static <T> List<T> copyList(final List<Object> f, final Class<T> t) {
        if (CollectionUtils.isEmpty(f)) return CollectionUtil.newArrayList();
        return f.stream().map(x -> {
            BeanUtil.copyProperties(x, ClassTypeUtils.newInstance(t));
            return (T)x;
        }).collect(Collectors.toList());
    }

    private static String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<String>();
        for (java.beans.PropertyDescriptor pd : pds) {
            //check if value of this property is null then add it to the collection
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) emptyNames.add(pd.getName());
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }


}
